package cn.stard.pet.service.impl;

import cn.stard.basic.exception.BusinessException;
import cn.stard.basic.util.BaiduAuditUtils;
import cn.stard.basic.util.CodeGenerateUtils;
import cn.stard.basic.util.DistanceUtil;
import cn.stard.basic.util.Point;
import cn.stard.order.domain.OrderPetAcquisition;
import cn.stard.order.mapper.OrderPetAcquisitionMapper;
import cn.stard.org.domain.Shop;
import cn.stard.org.mapper.ShopMapper;
import cn.stard.pet.domain.HandlerMsgDto;
import cn.stard.pet.domain.Pet;
import cn.stard.pet.domain.SearchMasterMsg;
import cn.stard.pet.domain.SearchMasterMsgAuditLog;
import cn.stard.pet.mapper.PetMapper;
import cn.stard.pet.mapper.SearchMasterMsgAuditLogMapper;
import cn.stard.pet.mapper.SearchMasterMsgMapper;
import cn.stard.pet.query.SearchMasterMsgQuery;
import cn.stard.pet.service.ISearchMasterMsgService;
import cn.stard.basic.service.impl.BaseServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.awt.*;
import java.util.Date;
import java.util.List;
//- 寻主消息录入成功是待审核状态，不可能直接就是审核通过的信息，需要去审核填写的内容是否合法、内容是否正确
//- 寻主消息只有被平台审核没问题后，才分发给最近店铺，如果方圆50公里没有店铺那么放入寻主池，方便人工干预
//- 审核状态分析
//  - 待审核：初始状态为待审核
//  - 审核通过：记录审核日志、分配寻主消息到方圆50公里内的店铺并发送短信通知店铺，如果没有找到店铺，放入寻主池
//
//  - 审核失败-驳回：记录审核日志、直接驳回，用户可以修改重新提交
//
//  - 拒绝：直接没有机会了
//
//
//- 审核方案
//  - 平台管理员人工审核，与店铺审核一致
//  - 自动审核：可以使用百度人工智能技术来审核，除了不合法信息还可以根据公司业务定制审核方案
//
//- 方案对比
//
//  - 人工审核的方式比较简单，适用于审核数量少、及时性要求不高的用户，同时也存在以下问题：
//
//    - 受审核人员状态影响大，容易出现人为差错，影响用户注册
//    - 人工审核及时性差，不能在第一时间对注册用户进行审核，影响用户体验
//    - 对于冒充、伪造的用户注册信息，无法凭肉眼和经验作出有效分辨，给企业带来潜在风险
//    - 每次人员流动后，都需要对新的审核人员进行培训，成本高，周期长
//
//
//  - 自动审核会根据企业平台的具体需求和用户场景搭建对应的识别和验证流程，相比人工审核具有下列优点
//
//    - 调试成功后，系统出现人为误差几率极低，极大的提高了审核效率
//
//    - 极速审核，用户提交后马上就能自动识别自动验证，并返回验证结果
//
//    - 精准性极高，能有效识别用户恶意提交的冒充和伪造信息
//
//    - 审核成本低，几乎不占用相关人力资源，节省运营费用
//
//- 自动审核实现分析
//
//  - 因为用户填写了信息后，不管是否审核通过，都应该让用户能够在个人中心看得到，所以我们第一步先将用户发布的寻主信息进行入库，这样用户体验感也比较好
//
//  - 调用统一的审核接口，前面店铺入组已经写过
//
//    - 文本审核
//
//    - 图片审核
//
//    - 声音审核
//
//    - 视频审核
//
//  - 自动审核通过，分发消息给店铺，并发送短信或者邮件通知店铺。分发不成功放入寻主池
//
//    - 查询所有店铺，获取小于50公里的店铺
/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author stard
 * @since 2022-07-19
 */
@Service
public class SearchMasterMsgServiceImpl extends BaseServiceImpl<SearchMasterMsg> implements ISearchMasterMsgService {
@Autowired
private SearchMasterMsgMapper searchMasterMsgMapper;

    @Autowired
    private ShopMapper shopMapper;
    @Autowired
    private SearchMasterMsgAuditLogMapper searchMasterMsgAuditLogMapper;

    @Autowired
    private OrderPetAcquisitionMapper orderPetAcquisitionMapper;

    @Autowired
    private PetMapper petMapper;

    @Override
    public void publicsh(SearchMasterMsg searchMasterMsg) {
        // 因为此业务如果审核不通过一直让用户输入业务,或者清空页面会造成用户体验不好所以这边先直接保存
        searchMasterMsgMapper.save(searchMasterMsg);
        StringBuffer sbf = new StringBuffer();
        sbf.append(searchMasterMsg.getName())
                .append(searchMasterMsg.getAddress())
                .append(searchMasterMsg.getCoatColor())
                .append(searchMasterMsg.getTitle());
        // 把
        if (!BaiduAuditUtils.TextCensor(sbf.toString())){
            // 如果审核失败.我们设置主状态为待审核.并且保存日志
            searchMasterMsg.setState(0);
            // 并且打印审核日志
            SearchMasterMsgAuditLog log = new SearchMasterMsgAuditLog();
            // 保存id
                log.setMsgId(searchMasterMsg.getId());
            // 保存时间
            log.setAuditTime(new Date());
            // 保存审核日志消息
            log.setNote("文字审核失败，可能失败的原因：宠物毛色、寻主标题、地址、宠物名称");
            searchMasterMsgAuditLogMapper.save(log);
        }else {
            // 到此处应该是审核通过了，那么我们应该判断距离，判断用户填写的上门收购宠物的地址方圆50公里是否有店铺存在，如果存在分配店铺
            List<Shop> shops = shopMapper.loadAll();
            // 获取用户地址经纬度
            Point point = DistanceUtil.getPoint(searchMasterMsg.getAddress());
            // 调用工具类计算得到50公里内所有店铺
            Shop shop = DistanceUtil.getNearestShop(point, shops);
            // 找到店铺，给当前寻主消息绑定店铺，也就是把当前寻主消息任务分配给店铺
            if (shop != null){
                // 把当前寻主消息绑定给店铺
                searchMasterMsg.setShopId(shop.getId());
            }
            searchMasterMsg.setState(1);
            // 没有找到店铺进入了寻主池
            // 寻主池：就是当寻主消息的shopId为null的时候，那么就意味着这个寻主消息没有被店铺接受任务，那么这个时候此寻主消息就在寻主池中
        }
        // 修改寻主消息修改寻主状态
        searchMasterMsgMapper.update(searchMasterMsg);
    }

    @Override
    public void accept(HandlerMsgDto handlerMsgDto) {
        Long handler = handlerMsgDto.getHandler();
        String note = handlerMsgDto.getNote();
        Long id = handlerMsgDto.getMsgId();

        if (handler==null
                || StringUtils.isEmpty(note)
               || id ==null
           ){
            throw new BusinessException("参数异常！,店铺没有消息");
        }

        // 1.确定是否已经被接单，万一有两个人同时点击接单，怎么办？以后我们用加锁处理，现在我们先查询一下
        /*
            情况分析：state != -1 searcherMasterMsgId = handlerMsgDto.msgId
                1.当前寻主消息是第一次被接单，那么没有在收购订单中应该查询不到
                2.当前寻主消息不是第一次被接单了，那么说明之前生成过
                3.如何判定是否可以接单：
                    1.如果查询不到收购单那么就可以接单
                    2.即便查询的到收购单，但是收购单的消息需要为-1，只要不是-1，并且查询到了，都不能接单
        */
            // 调用当前id查看他是不是收购单,因为两张表关联了
        OrderPetAcquisition orderPetAcquisition =  orderPetAcquisitionMapper.loadByOrderReceived(handlerMsgDto.getMsgId());
        // 如果查出来有数据证明他有收购单,就不能再接单了
        if (orderPetAcquisition != null){
            throw new BusinessException("该订单已经被人收购了！");
        }

        // 如果走到下面就说明没有被别人收购那么我们需要获得寻主消息然后保存到宠物详情再添加到收购单


        // 1.查询发布的寻主消息
        SearchMasterMsg searchMasterMsg = searchMasterMsgMapper.loadById(handlerMsgDto.getMsgId());
        // 2.生成宠物信息，并保存
        Pet pet = new Pet();
        pet.setName(searchMasterMsg.getName());
        pet.setCostprice(searchMasterMsg.getPrice());
        pet.setTypeId(searchMasterMsg.getPetType());
        pet.setShopId(searchMasterMsg.getShopId());
        pet.setSearchMasterMsgId(searchMasterMsg.getId());
        petMapper.save(pet); // 需要返回主键
        // 3.初始化订单对象并保存 添加收购单
        orderPetAcquisition = initOrderPetAcquisition(handlerMsgDto, searchMasterMsg, pet);
        orderPetAcquisitionMapper.save(orderPetAcquisition);




    }

    // ctrl + alt + m 快速抽取代码为方法
    private OrderPetAcquisition initOrderPetAcquisition(HandlerMsgDto handlerMsgDto, SearchMasterMsg searchMasterMsg, Pet pet) {
        // 3.生成收购单，本来也应该抽取一个方法，但是等会儿要教你们一个操作，所以等会儿再抽
        OrderPetAcquisition orderPetAcquisition = new OrderPetAcquisition();
        // 使用工具类生成订单编号
        String orderSn = CodeGenerateUtils.generateOrderSn(searchMasterMsg.getUserId());
        orderPetAcquisition.setOrderSn(orderSn);
        orderPetAcquisition.setDigest(handlerMsgDto.getNote());
        // 最迟的处理订单的时间
        orderPetAcquisition.setLastcomfirmtime(new Date(System.currentTimeMillis() + 2*24*60*60*1000));
        // 这时候还不是最终价格，因为我们销售人员可以去讲价，加价之后的才是最终价格
        orderPetAcquisition.setPrice(searchMasterMsg.getPrice());
        orderPetAcquisition.setPetId(pet.getId());
        orderPetAcquisition.setUserId(searchMasterMsg.getUserId());
        orderPetAcquisition.setShopId(searchMasterMsg.getShopId());
        orderPetAcquisition.setAddress(searchMasterMsg.getAddress());
        orderPetAcquisition.setEmpId(handlerMsgDto.getHandler());
        orderPetAcquisition.setSearchMasterMsgId(searchMasterMsg.getId());
        return orderPetAcquisition;
    }
}
